package kt.com.bilin.coin.helper

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.text.TextUtils
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.bilin.coin.BuildConfig
import kt.com.bilin.coin.ui.dialog.showAlertDialog
import kt.com.bilin.coin.ui.dialog.UpdateDownloadDialog
import kt.com.bilin.coin.ui.dialog.UpdateHintDialog
import kt.com.bilin.coin.utils.ActivityManger
import kt.com.bilin.coin.utils.Logger
import kt.com.bilin.coin.viewmodel.BackgroundCommonApi
import org.lzh.framework.updatepluginlib.UpdateBuilder
import org.lzh.framework.updatepluginlib.base.DownloadCallback
import org.lzh.framework.updatepluginlib.base.DownloadWorker
import org.lzh.framework.updatepluginlib.impl.HttpException
import org.lzh.framework.updatepluginlib.model.CheckEntity
import org.lzh.framework.updatepluginlib.model.Update
import org.lzh.framework.updatepluginlib.util.SafeDialogHandle
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL


object UpdateHelper {
    private const val TIME = 1 * 60 * 60 * 1000// 1小时后再次检查更新
    private var lastCheckTime: Long = 0
    fun checkUpdate() {
        Logger.e("checkUpdate==>")
        if (System.currentTimeMillis() - lastCheckTime > TIME) {
            lastCheckTime = System.currentTimeMillis()
            UpdateBuilder.create().setUrl("update").setCheckWorker(CheckWorker::class.java).setUpdateParser(UpdateParser()).setUpdateChecker(UpdateChecker()).setCheckNotifier(CheckNotifier()).setDownloadWorker(DefaultDownloadWorker::class.java)
                    .setDownloadNotifier(DownloadNotifier()).setFileChecker(FileChecker()).setUpdateStrategy(UpdateStrategy()).check()
        }
    }

    class CheckWorker : org.lzh.framework.updatepluginlib.base.CheckWorker() {
        override fun useAsync() = true
        override fun asyncCheck(entity: CheckEntity?) {
            BackgroundCommonApi.appVersion {
                if (it != null) {
                    onResponse(JSONObject.toJSONString(it))
                } else {
                    onError(RuntimeException("拉取新版本失败"))
                }
            }
        }
    }

    class UpdateParser : org.lzh.framework.updatepluginlib.base.UpdateParser() {
        override fun parse(response: String?): Update {
            val jsonObject = JSON.parseObject(response)
            Logger.e("jsonObject==>${jsonObject}")
            val update = Update()
            update.versionName = jsonObject.getString("status") ?: "0"
            update.updateContent = jsonObject.getString("content")
            update.isForced = jsonObject.getIntValue("status") == 2
            update.updateUrl = jsonObject.getString("link")
            return update
        }
    }

    class UpdateChecker : org.lzh.framework.updatepluginlib.base.UpdateChecker() {
        override fun check(update: Update) = update.versionName.toInt() > 0
    }

    class CheckNotifier : org.lzh.framework.updatepluginlib.base.CheckNotifier() {
        override fun create(activity: Activity) = UpdateHintDialog(activity, update, this)
    }

    class DownloadNotifier : org.lzh.framework.updatepluginlib.base.DownloadNotifier() {
        override fun create(update: Update, activity: Activity): DownloadCallback {
            val dialog = UpdateDownloadDialog(activity, update)
            SafeDialogHandle.safeShowDialog(dialog)
            return object : DownloadCallback {
                override fun onDownloadStart() {}
                override fun onDownloadComplete(file: File) = SafeDialogHandle.safeDismissDialog(dialog)
                override fun onDownloadProgress(current: Long, total: Long) {
                    val progress = (current * 1.0f / total * 100).toInt()
                    dialog.setProgress(progress)
                }

                override fun onDownloadError(t: Throwable) {
                    Logger.e(t)
                    SafeDialogHandle.safeDismissDialog(dialog)
                    createRestartDialog()
                }
            }
        }

        private fun createRestartDialog() {
            ActivityManger.getCurActivity().showAlertDialog {
                title(title = "下载apk失败")
                message(message = "是否重新下载？")
                positiveButton { restartDownload() }
                negativeButton(name = if (update.isForced) "退出" else "取消") {
                    if (update.isForced) {
                        ActivityManger.exit()
                    } else {
                        dismiss()
                    }
                }
            }
        }
    }

    class FileChecker : org.lzh.framework.updatepluginlib.base.FileChecker() {
        override fun onCheckBeforeDownload() = false
        override fun onCheckBeforeInstall() {}
    }

    class UpdateStrategy : org.lzh.framework.updatepluginlib.base.UpdateStrategy() {
        override fun isShowUpdateDialog(update: Update) = true
        override fun isShowDownloadDialog() = true
        override fun isAutoInstall() = true
    }

    fun isUpdate(versionName: String, serviceVersion: String): Boolean {
        Logger.e("versionName==<${versionName}<===>${serviceVersion}")
        var isUpdate = false
        try {
            val versionNameArr = versionName.split(".").toTypedArray()
            val serviceVersionArr = serviceVersion.split(".").toTypedArray()
            // 本地小于服务器更新1.0  1.1
            for (i in 0 until Math.min(versionNameArr.size, serviceVersionArr.size)) {
                val local = versionNameArr[i].toInt()
                val service = serviceVersionArr[i].toInt()
                if (local < service) {
                    isUpdate = true
                    break
                } else if (local == service) { // 跳过
                } else { // 本地大于远端，不更新
                    break
                }
            }
            if (!isUpdate && versionNameArr.size < serviceVersionArr.size) {
                isUpdate = true
            }
        } catch (e: Exception) {
            Logger.e(e)
        }
        return isUpdate
    }

    /**
     * 启动到app详情界面
     *
     * @param appPkg
     * App的包名
     * @param marketPkg
     * 应用商店包名 ,如果为""则由系统弹出应用商店列表供用户选择,否则调转到目标市场的应用详情界面，某些应用商店可能会失败
     */
    fun launchAppDetail(context: Context, appPkg: String): Boolean {
        if (BuildConfig.DEBUG) return false
        val intent = Intent(Intent.ACTION_VIEW)
        intent.data = Uri.parse("market://details?id=$appPkg")
        val keys = getKeys(context)
        if (keys != null) {
            intent.setClassName(keys[0], keys[1])
        }
        //修复某些老手机会因为找不到任何市场而报错
        if (isIntentAvailable(context, intent)) {
            context.startActivity(intent)
            return true
        } else {
            return false
        }
    }

    //小米应用商店
    private const val PACKAGE_MI_MARKET = "com.xiaomi.market"
    private const val MI_MARKET_PAGE = "com.xiaomi.market.ui.AppDetailActivity"

    //VIVO应用商店
    private const val PACKAGE_VIVO_MARKET = "com.bbk.appstore"
    private const val VIVO_MARKET_PAGE = "com.bbk.appstore.ui.AppStoreTabActivity"

    //OPPO应用商店
    private const val PACKAGE_OPPO_MARKET = "com.oppo.market"
    private const val OPPO_MARKET_PAGE = "a.a.a.aoz"

    //华为应用商店
    private const val PACKAGE_HUAWEI_MARKET = "com.huawei.appmarket"
    private const val HUAWEI_MARKET_PAGE = "com.huawei.appmarket.service.externalapi.view.ThirdApiActivity"
    private fun getKeys(context: Context): Array<String>? = when {
        isPackageExist(context, PACKAGE_MI_MARKET) -> arrayOf(PACKAGE_MI_MARKET, MI_MARKET_PAGE)
        isPackageExist(context, PACKAGE_VIVO_MARKET) -> arrayOf(PACKAGE_VIVO_MARKET, VIVO_MARKET_PAGE)
        isPackageExist(context, PACKAGE_OPPO_MARKET) -> arrayOf(PACKAGE_OPPO_MARKET, OPPO_MARKET_PAGE)
        isPackageExist(context, PACKAGE_HUAWEI_MARKET) -> arrayOf(PACKAGE_HUAWEI_MARKET, HUAWEI_MARKET_PAGE)
        else -> null
    }

    /**
     * @param context
     * @param packageName
     * @return
     * @Title isPackageExist
     * @Description .判断package是否存在
     * @date 2013年12月31日 上午9:49:59
     */
    @SuppressLint("WrongConstant")
    fun isPackageExist(context: Context, packageName: String?): Boolean {
        val manager = context.packageManager
        val intent = Intent().setPackage(packageName)
        val infos = manager.queryIntentActivities(intent, PackageManager.GET_INTENT_FILTERS)
        return !(infos.size < 1)
    }

    /**
     * 检测 响应某个Intent的Activity 是否存在
     * @param context
     * @param intent
     * @return
     */
    @SuppressLint("WrongConstant")
    fun isIntentAvailable(context: Context, intent: Intent?): Boolean {
        val packageManager = context.packageManager
        val list = packageManager.queryIntentActivities(intent, PackageManager.GET_ACTIVITIES)
        return list.size > 0
    }
}

class DefaultDownloadWorker : DownloadWorker() {
    private var urlConn: HttpURLConnection? = null
    private var original: File? = null
    private var bak: File? = null
    private var contentLength: Long = 0

    @Throws(java.lang.Exception::class)
    override fun download(url: String?, target: File?) {
        original = target
        val httpUrl = URL(url)
        urlConn = httpUrl.openConnection() as HttpURLConnection
        setDefaultProperties()
        urlConn!!.connect()
        val responseCode = urlConn!!.responseCode
        if (responseCode == 301 || responseCode == 302) {
            val newUrl = urlConn!!.getHeaderField("location")
            urlConn!!.disconnect()
            urlConn = null
            download(newUrl, original)
            return
        } else if (responseCode < 200 || responseCode >= 300) {
            urlConn!!.disconnect()
            throw HttpException(responseCode, urlConn!!.responseMessage)
        }
        contentLength = urlConn!!.contentLength.toLong()
        // 使用此bak文件进行下载。辅助进行断点下载。
        if (checkIsDownAll()) {
            urlConn!!.disconnect()
            urlConn = null
            // notify download completed
            sendDownloadComplete(original)
            return
        }
        createBakFile()
        val writer = supportBreakpointDownload(httpUrl)
        var offset = bak!!.length()
        val inputStream = urlConn!!.inputStream
        val buffer = ByteArray(8 * 1024)
        var length: Int
        var start = System.currentTimeMillis()
        while (inputStream.read(buffer).also { length = it } != -1) {
            writer.write(buffer, 0, length)
            offset += length.toLong()
            val end = System.currentTimeMillis()
            if (end - start > 1000) {
                sendDownloadProgress(offset, contentLength)
                start = System.currentTimeMillis()
            }
        }
        urlConn!!.disconnect()
        writer.close()
        urlConn = null
        renameAndNotifyCompleted()
    }

    private fun checkIsDownAll(): Boolean {
        return original!!.length() == contentLength && contentLength > 0
    }

    @Throws(IOException::class)
    private fun supportBreakpointDownload(httpUrl: URL): FileOutputStream {
        val range = urlConn!!.getHeaderField("Accept-Ranges")
        if (TextUtils.isEmpty(range) || !range.startsWith("bytes")) {
            bak!!.delete()
            return FileOutputStream(bak, false)
        }
        val length = bak!!.length()
        urlConn!!.disconnect()
        urlConn = httpUrl.openConnection() as HttpURLConnection
        urlConn!!.setRequestProperty("RANGE", "bytes=$length-$contentLength")
        setDefaultProperties()
        urlConn!!.connect()
        val responseCode = urlConn!!.responseCode
        if (responseCode < 200 || responseCode >= 300) {
            throw HttpException(responseCode, urlConn!!.responseMessage)
        }
        return FileOutputStream(bak, true)
    }

    @Throws(IOException::class)
    private fun setDefaultProperties() {
        urlConn!!.setRequestProperty("Content-Type", "text/html; charset=UTF-8")
        urlConn!!.requestMethod = "GET"
        urlConn!!.connectTimeout = 10000
    }

    // 创建bak文件。
    private fun createBakFile() {
        bak = File(String.format("%s_%s", original!!.absolutePath, contentLength))
    }

    private fun renameAndNotifyCompleted() {
        original!!.delete()
        bak!!.renameTo(original)
        sendDownloadComplete(original)
    }
}